package com.lry.proxy;

import com.lry.common.CommonConstants;
import com.lry.router.Router;
import com.lry.rpc.netty.client.RpcClient;
import com.lry.spi.LoadLevel;
import com.lry.util.CollectionUtils;
import com.lry.util.StringUtils;

import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.util.HashMap;
import java.util.Map;
import java.util.Set;
import java.util.TreeSet;


@LoadLevel(name = "jdk")
public class JdkProxy extends AbstractProxy implements Proxy {

    private Router router;
    private Set<String> excludeMethod = new TreeSet();
    private Set<String> includeMethod = new TreeSet();
    private String group;
    private String version;

    public JdkProxy(Router router,String[] includeMethod,String[] excludeMethod,String group,String version){
        this.router = router;
        this.group = group;
        this.version = version;
        if(CollectionUtils.isNotEmpty(includeMethod)){
            for (String s : includeMethod) {
                this.includeMethod.add(s);
            }
        }
        if(CollectionUtils.isNotEmpty(excludeMethod)){
            for (String s : excludeMethod) {
                this.excludeMethod.add(s);
            }
        }
    }

    @Override
    public <T> T getProxy(Class clazz) {
       return getProxy(clazz,null);
    }

    @Override
    public <T> T getProxy(Class clazz, String implName) {
        return (T) java.lang.reflect.Proxy.newProxyInstance(clazz.getClassLoader(), new Class[]{clazz},
                new JdkInvocationHandler(clazz,implName));
    }

    private class JdkInvocationHandler implements InvocationHandler{

        private Class clazz;
        private String implName;

        public JdkInvocationHandler(Class clazz, String implName) {
            this.clazz = clazz;
            this.implName = implName;
        }

        @Override
        public Object invoke(Object o, Method method, Object[] args)   throws Throwable {
            if(excludeMethod.contains(method.getName())){
                return null;
            }
            if(!includeMethod.isEmpty()&&!includeMethod.contains(method.getName())){
                return null;
            }
            Map<String,Object> att = new HashMap<>();
            if(StringUtils.isNotBlank(implName)){
                att.put(CommonConstants.SPEC_IMPL_NAME_KEY,implName);
            }
            if(StringUtils.isNotBlank(version)){
                att.put(CommonConstants.SPEC_VERSION_KEY,version);
            }
            if(StringUtils.isNotBlank(group)){
                att.put(CommonConstants.SPEC_GROUP_KEY,group);
            }
            return enhance(att,method,args,clazz,router);

        }

    }

}
